<template>
    <div class="render-content" v-draggable="[renderTree,options]" :data-node-id="isRoot?'root':''">
       <div v-for="(node,index) in renderTree" :key="node.id" >
            <div 
            class="render-class" 
            :class="{'hover-class':node.isHover}"
            @mouseenter.stop="handleMouseEnter($event,node)" 
            @mouseleave.stop="handleMouseLeave($event,node)"
            @click.stop="handleClick(node)"
            >
                <div class="operate-container" v-if="node.operateFlag"><!---->
                    <div class="del">
                        <!--自动导入icon图标的icon,只需要以{prefix}-{collection}-{icon}格式来使用-->
                        <!--element-plus 的图标库名称是 “ep”，默认前缀是 “i”，-->
                        <el-icon class="del-class"><i-ep-delete-filled /></el-icon>
                    </div>
                </div>
                <component  
                :is="node.currentComponent"
                :item-props="node.props || {}"
                v-on="node.events || {}"
                :data-node-id="node.id"
                :columns="node.columns || []"
                >
                    <template   v-for="(tip,tipIndex) in getSlots(node)" :key="tip.id" #[tip.slotKey]>
                        <render :parentId="tip.parentId"  :renderTree="tip.children" @child-hover="childHover"/>  
                    </template>
                </component>
            </div>
            
        </div>
    </div>
</template>

<script lang="ts" setup>
    import {ref,defineEmits } from 'vue'
    import type { Component, PropType } from 'vue';
    import loadComponent from '@/protocol/index_map';
    import {useRenderTreeStore} from '@/store/renderTree'
    import getDSL from '@/protocol'
    import {  vDraggable,DraggableEvent  } from 'vue-draggable-plus';

    /**
     * 该页面的结构思路：
     * ——采用的是一个对象嵌套的结构来表明一个组件树的定义。根组件是对象，子组件在根组件的children数组中，然后依次添加，最终形成渲染组件树
     * ——通过动态组件+递归组件的方式来渲染组件树
     * 问题1:
     * ——显式声明自身——递归组件的前提，但是在script-setup中，会自动将组件名注册成全局组件，故可以直接在模板中使用
     *   如果是选项式vue3的写法，则需要声明自身组件，使用defineComponent，且只能在选项式中使用，不能在script-setup语法中使用
     * 问题2：
     * ——在使用动态组件component时，如果想在动态组件标签内插入其他内容，便要使用插槽。
     */

    const store=useRenderTreeStore();
    //接收参数——接收的是递归时自身传递给自身的参数
    const props=defineProps({
        renderTree:{
            type:Array as PropType<ComponentMeta[]>, 
            required:true
        },
        parentId:{
            type:String,
            required:true
        }
    })
    //临时新增的属性operateFlag
    type render_type=ComponentMeta & {
        operateFlag:boolean,
        isHover:Boolean,//组件是否被鼠标移入，是否需要展示遮罩
        clickFlag:Boolean //组件是否被点击选中
    }
    const renderTree=ref<render_type[]>(
        props.renderTree.map(node => ({
            ...node,
            operateFlag: false, // 初始化临时属性
            isHover:false,
            clickFlag:false 
        }))
    );//创建副本，便于修改传递过来的renderTree
    //是否是根节点
    let isRoot=ref<boolean>(null)
    if(props.parentId=='root'){
        isRoot.value=true
    }else{
        isRoot.value=false
    }

    //显示删除等图表按钮
    const emit=defineEmits<{
        (e:'child-hover'):void //子节点hover的时候，通知父节点取消
    }>()
    let temp='';//临时变量
    const handleMouseEnter=(e:Event,node:render_type)=>{
        // console.log('鼠标移入',node,renderTree.value)
        if(!node.clickFlag){
            const nodeIndex=renderTree.value.findIndex(item=>item.id==node.id)
            renderTree.value[nodeIndex].isHover=true;
            console.log('------',renderTree.value[0])
            emit('child-hover');//通知父节点，已hover  
        }
           
    }
    const handleMouseLeave=(e:Event,node:render_type)=>{
        // console.log('鼠标移出',node)
        if(!node.clickFlag){
            const nodeIndex=renderTree.value.findIndex(item=>item.id==node.id)
            renderTree.value[nodeIndex].isHover=false;
        }
    }
    //接收子级传递的值
    const childHover=()=>{
        //清空父级所有的hover
        renderTree.value.forEach(node=>{
            node.isHover=false; 
            node.clickFlag=false;
        })
    }
    const handleClick=(node:render_type)=>{
        //清空所有的父级的hover和click和operateFlag
        renderTree.value.forEach(node=>{
            node.isHover=false; 
            node.clickFlag=false;
            node.operateFlag=false;
        })
        const nodeIndex=renderTree.value.findIndex(item=>item.id==node.id);
        renderTree.value[nodeIndex].clickFlag=true;
        renderTree.value[nodeIndex].isHover=true;
        renderTree.value[nodeIndex].operateFlag=true;
        console.log('lllll',node,renderTree.value)
        store.saveComponentId(node.id); //保存id
    }

    //监听renderTree
    // watch(()=>props.renderTree,(newVal,oldVal)=>{
    //     console.log('监听--',newVal)
    // },{deep:true})

    //额外处理渲染区中的不同组件插槽展示，保证模板中的功能简洁，不用硬编码v-for和v-if做判断
    const getSlots=(node:ComponentMeta)=>{
        let slots=[]; 
        if(node.type=='Gridlayout'){
            if(node.columns && node.columns.length>0){
                node.columns.forEach((item:ColumnsChildren,index:Number)=>{
                    let obj={
                        slotKey:'column-'+index,
                        parentId:node.id,
                        id:item.id,
                        children:item.children
                    }
                    slots.push(obj)
                })
            } 
        }else{
            let obj={
                slotKey:'content',
                parentId:node.id,
                id:node.id+'#content',
                children:node.children
            }
            slots.push(obj);
        }
        // console.log('slots-----',slots)
        return slots;
    }

    const options = {
        animation: 150,
        group:{
            name:'component',
            put:true,
            pull:false
        },
        onAdd(e:DraggableEvent) {
            console.log('拖拽完成，添加元素。且找到拖拽完成时的容器元素',e,props,renderTree.value)
            const component_DSL=getDSL(e.data.title)
            const newIndex=e.newIndex; //拖拽完成后，新元素的索引位置。
            // console.log('88888',e.target.closest('.drop-zone'))
            const dropZone=e.target.closest('.drop-zone');//向上查找含有.drop-zone的元素
            if(!dropZone){ 
                /**
                 * 其父级组件容器不是Gridlayout组件
                 */
                //通过newIndex进行有顺序的添加，因为不知道在列表之前添加还是之后添加，需要保证视图和渲染树的数据保持一致
                store.addRenderTree(props.parentId,component_DSL,newIndex)
            }else{
                /**
                 * 其父级组件容器是Gridlayout组件
                 */
                const columnIndex=dropZone.getAttribute('data-column');
                //store中的将DSL保存到渲染树上的方法
                store.addToMultiColumn(props.parentId,columnIndex,component_DSL,newIndex)
            }
            console.log('treeArr---',store.treeArr,store.treeMap)
        },
    }

</script>
<style lang="scss" scoped>
.render-content{
    min-height:100px; //必须设置高度，防止高度为0，其拖拽无法找到目标元素，无法实现拖拽的问题
    border:1px dashed #ccc;
    padding:10px;
    .render-class{
        position:relative;
        padding:10px;
        .operate-container{
            width:50px;
            // height:20px;
            position: absolute;
            right:0px;
            top:0;
            z-index:11;
            background-color:#409eff;
            border-bottom-left-radius: 10px;
            text-align: right;
            .del{
                width:20px;
                margin-left:5px;
                .del-class{
                    color:#fff;
                    font-size:18px;
                }
            }
        }
    }
    .hover-class{
        &::before{
            content: '';
            position: absolute; 
            top: 0;
            left: 0;
            right: 0;
            bottom: 0; 
            background-color: rgb(220, 220, 220, 0.5);; /* 半透明黑色遮罩（可自定义） */
            z-index: 10; 
            border-radius: 4px;
            transition: background-color 0.2s;
            pointer-events: none; /* 关键：允许鼠标事件穿透遮罩层 */
        }
    }
    
}
</style>